package com.typhoon.spring_shiro.dao.ha;

import java.util.ArrayList;

/**
 * 负载均衡器
 * (1)支持各节点间的负载均衡
 * (2)支持每个节点的权重设定
 * (3)支持单个节点的动态故障隔离和故障恢复
 * (4)支持每个节点的动态权重修正系数设定
 *
 * @author zhangshsh 2013-09-06 作成
 */
public class MyLoadBalance {
    /**
     * 初始化 serverList
     *
     * @param serverList serverList
     */
    public static void init(ArrayList<BalanceNodeBean> serverList) {
        int             len  = serverList.size();
        BalanceNodeBean bean = null;
        for (int i = 0; i < len; i++) {
            bean = serverList.get(i);

            // init correctionWeight to 0
            bean.setCorrectionWeight(0);

            // init currentWeight to 0
            bean.setCurrentWeight(0);
        }
    }

    /**
     * 取得 将使用的 BalanceNode index
     *
     * @param serverList serverList
     * @return 将使用的 BalanceNode index
     */
    public static int getForwardServerIndex(
            ArrayList<BalanceNodeBean> serverList) {
        // check para
        if (serverList == null) {
            return -1;
        }

        int len = serverList.size();
        if (len == 0) {
            // (1)无server
            return -1;
        }

        int result = -1;
        if (len == 1) {
            // (2)仅有一台server时
            if (serverList.get(0).getDownFlag() == 1) {
                // 无可用的server
                result = -1;
            } else {
                // 仅这一台
                result = 0;
            }
            return result;
        }

        // (3)有多台后端服务器
        BalanceNodeBean bestBean = null;
        BalanceNodeBean tempBean = null;

        float currentWeight = 0;
        // 所有服务器总权重
        float totalEffectiveWeight = 0;
        // 遍历所有服务器, 按照各台服务器的当前权值进行选择
        for (int i = 0; i < len; i++) {
            tempBean = serverList.get(i);

            if (tempBean.getDownFlag() == 1) {
                // Down掉的server,将被skip.
                continue;
            }

            // 计算当前权值，包含权重修正系数
            currentWeight = tempBean.getCurrentWeight() + tempBean.getWeight()
                    * (1 + tempBean.getCorrectionWeight());
            tempBean.setCurrentWeight(currentWeight);

            // 总的权重计算，包含权重修正系数
            totalEffectiveWeight += tempBean.getWeight()
                    * (1 + tempBean.getCorrectionWeight());

            // 选择
            if (bestBean == null
                    || bestBean.getCurrentWeight() < tempBean
                    .getCurrentWeight()) {
                // 选择当前权重最大的serverNode
                bestBean = tempBean;
                //
                result = i;
            }
        }

        if (bestBean == null) {
            // 无可用的server
            return -1;
        }

        if (bestBean != null) {
            // 该服务器这次被选中，因此要降低权值,以便下次计算。
            currentWeight = bestBean.getCurrentWeight() - totalEffectiveWeight;
            bestBean.setCurrentWeight(currentWeight);
        }

        return result;
    }
}
